/*
 CON_AT_MSH=0: AT模式: 配合 Xmodem1K 更新固件
=>: AT+fun(a,b,c)\r\n

CON_AT_MSH=1: MSH模式: 调试
=>: fun a b \n

**/



#ifndef _AT_SHELL_H
#define _AT_SHELL_H

#include "stdint.h"
#include "string.h"

//模式  0:AT    1:MSH
#define  CON_AT_MSH  1
//方法数
#define  CON_AT_METHOD_NUM     20
#define  FINSH_CMD_SIZE  80             //最长命令尺寸
#define  RT_FINSH_ARG_MAX       6        //参数个数
#define  FINSH_HISTORY_LINES    3       //历史命令条数

#define  CON_AT_R_SUCCESS   0    // 成功
#define  CON_AT_R_ERR_ARG   1    // 参数错误
#define  CON_AT_R_ERR_NO_CMD   2  //无此命令
#define  CON_AT_R_ERR_EXEC_FAIL 3  //执行失败   


typedef  int (*ATServerFun)(int argc, char** argv);
typedef  int (*ATWriteFun)(uint8_t* buf, uint32_t len);
typedef struct {
	char methodName[20];
	char helpInfo[20];
	ATServerFun  atFun;
	void* userData;
}AT_CMD_ENTRY_TypeDef;


#ifdef __cplusplus
class AtShell {
private:
	AT_CMD_ENTRY_TypeDef* m_cmdList;
	uint32_t m_cmdSize;
	int      m_cmdNum;
	char m_buf[FINSH_CMD_SIZE];
	uint32_t m_bufLen;
	uint32_t m_importMs;
	uint32_t m_lock;
	int  m_argc;
	char m_method[24];
	char* m_argv[RT_FINSH_ARG_MAX];
	ATWriteFun m_initWriteFun;
	ATWriteFun m_writeFun;
	virtual  bool  Parse(char* str);
public:
	AtShell();
	virtual ~AtShell();
	AT_CMD_ENTRY_TypeDef* ctx;
	virtual void   Init(ATWriteFun writeFun);
	virtual void   SetWriteFun(ATWriteFun writeFun);
	virtual void   ResetWriteFun();
	virtual char*  GetBuf() { return m_buf; };
	virtual int    GetCmdNum() { return m_cmdNum; };
	virtual bool   Regist(AT_CMD_ENTRY_TypeDef cmd);
	virtual bool   Regist(AT_CMD_ENTRY_TypeDef* cmdList, int cmdLen);
	virtual  bool  Exec(char* str);
	virtual  int   Import(uint8_t* buf, uint32_t len, uint32_t ms = 0);
	virtual  int   ImportForAt(uint8_t* buf, uint32_t len, uint32_t ms = 0);
	virtual  int   Printf(const char* format, ...);
	virtual  int   Output(long nLevel, const char* pszFileName, int nLineNo, const char* pszFmt, ...);
	virtual  int   PrintfBs(uint8_t* buf, uint32_t len);
	virtual  int   Write(uint8_t* buf, uint32_t len);
	virtual  int   Write(uint8_t data);
	virtual  int   Reply(uint8_t errCode);
	virtual  void  ShowVersion();
#if CON_AT_MSH==1
	uint16_t m_currentHistory;
	uint16_t m_historyCount;
	char m_cmdHistory[FINSH_HISTORY_LINES][FINSH_CMD_SIZE];
	int  m_stat;
	char    m_line[FINSH_CMD_SIZE];
	uint8_t m_linePosition;
	uint8_t m_lineCurpos;
	virtual  int  ImportForMsh(uint8_t* buf, uint32_t len, uint32_t ms = 0);
	virtual void  MshAddChar(char ch);
	virtual void  ShellPushHistory();
	virtual void  ShellAutoComplete(char* prefix);
	virtual void  MshAutoComplete(char* prefix);
	virtual bool  ShellHandleHistory();
#endif


};

extern AtShell g_atShell;

enum AT_LOG_LEVEL
{
	AT_LOG_LEVEL_TRACE,
	AT_LOG_LEVEL_DEBUG,
	AT_LOG_LEVEL_INFO,
	AT_LOG_LEVEL_WARNING,
	AT_LOG_LEVEL_ERROR,
	AT_LOG_LEVEL_SYSERROR,
	AT_LOG_LEVEL_FATAL,
	AT_LOG_LEVEL_CRITICAL
};

#if CON_AT_MSH==1
#define AT_FUN(fun)    #fun
#else
#define AT_FUN(fun)    "AT+"#fun  
#endif
#define AT_FILE_NAME(x)   strrchr(x,'\\')?strrchr(x,'\\')+1:x
#define AT_info(...)      g_atShell.Output(AT_LOG_LEVEL_INFO,__func__, __LINE__,__VA_ARGS__)
#define AT_debug(...)     g_atShell.Output(AT_LOG_LEVEL_DEBUG,AT_FILE_NAME(__FILE__), __LINE__,__VA_ARGS__)
#define AT_debug1(...)    g_atShell.Output(AT_LOG_LEVEL_DEBUG,__func__,__LINE__,__VA_ARGS__)
#define AT_error(...)     g_atShell.Output(AT_LOG_LEVEL_ERROR,__PRETTY_FUNCTION__,__LINE__,__VA_ARGS__)
#define AT_printf(format,...)  g_atShell.Printf(format,##__VA_ARGS__)
#define AT_printfBs(buf,len)  g_atShell.PrintfBs(buf,len)
#define rt_kprintf                  AT_printf
#define ATX_info(w,...)             g_atShell.SetWriteFun(w);AT_info(__VA_ARGS__);g_atShell.ResetWriteFun();
#define ATX_debug(w,...)            g_atShell.SetWriteFun(w);AT_debug(__VA_ARGS__);g_atShell.ResetWriteFun();
#define ATX_error(w,...)            g_atShell.SetWriteFun(w);AT_error(__VA_ARGS__);g_atShell.ResetWriteFun();
#define ATX_printf(w,...)           g_atShell.SetWriteFun(w);AT_printf(__VA_ARGS__);g_atShell.ResetWriteFun();
#define ATX_printfBs(w,buf,len)     g_atShell.SetWriteFun(w);g_atShell.PrintfBs(buf,len);g_atShell.ResetWriteFun(); 


#endif

//命令导出
#define AT_SHELL_EXPORT(cmdName,desc,fun,...)  AT_CMD_ENTRY_TypeDef fun##entrycmd={AT_FUN(cmdName),#desc,fun,__VA_ARGS__}; at_register(fun##entrycmd)

#ifdef __cplusplus
extern "C" {
#endif
	void  at_init(ATWriteFun writeFun);
	int   at_import(uint8_t* buf, uint32_t len, uint32_t ms);
	bool  at_register(AT_CMD_ENTRY_TypeDef cmd);
	bool  at_register_many(AT_CMD_ENTRY_TypeDef* cmdList, int cmdLen);
	int   at_printf(const char* format, ...);
	int   at_reply(uint8_t errCode);
	void  at_show_version();
#ifdef __cplusplus
}
#endif


#endif





/*
#include "AtShell.h"
#include "stdio.h"
int shell_write(uint8_t* buf, uint32_t len) {
    return  printf("%s", buf);
}
static int test01(int argc, char** argv) {
    AT_printf("argc %d:\r\n", argc);
    return 0;
}
int main() {
    at_init(shell_write);
    AT_SHELL_EXPORT(test01, "", test01);
    while (1) {
        uint8_t a = getchar();
        uint8_t bs[1] = { a };
        at_import(bs, 1, 0);
    }
    return 0;
}
**/